package www.superbytecode.com.bridge;

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.api.ProgressCallback;
import org.mybatis.generator.api.ShellCallback;
import org.mybatis.generator.config.*;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import www.superbytecode.com.enums.DBType;
import www.superbytecode.com.configuation.DBCommentGenerator;
import www.superbytecode.com.model.DBGenerator;
import www.superbytecode.com.model.DatabaseAttribute;
import www.superbytecode.com.util.ConfigHelper;
import www.superbytecode.com.util.DbUtil;
import www.superbytecode.com.util.TextUtil;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * All rights Reserved, Designed By www.super-bytecode.com
 *
 * @ProjectName superbytecode-builder
 * @Package www.superbytecode.com.bridge
 * @ClassName MybatisGeneratorBridge
 * @Description
 * @Author [Lance Ting]
 * @Date 2020/7/14 20:37
 * @Version V1.0
 * @Copyright: 2020 www.super-bytecode.com Inc. All rights reserved.
 * @TODO：本文件Lance Ting所作,如果转载或使用请标明具体出处!
 **/
public class MybatisGeneratorBridge {
    /**
     *
     */
    private static final Logger logger = LoggerFactory.getLogger(MybatisGeneratorBridge.class);
    /**
     *
     */
    private DBGenerator DBGenerator;
    /**
     *
     */
    private DatabaseAttribute selectedDatabaseAttribute;
    /**
     *
     */
    private ProgressCallback progressCallback;
    /**
     *
     */
    private List<IgnoredColumn> ignoredColumns;
    /**
     *
     */
    private List<ColumnOverride> columnOverrides;

    public MybatisGeneratorBridge() {
        initMybatisGeneratorBridge();
    }
    /**
     * @Description: [初始化]
     * @Title: initMybatisGeneratorBridge
     * @Author: Lance Ting
     * @Date: 2020-07-14
     * @Return: void
     * @Throws
     */
    private void initMybatisGeneratorBridge() {
        Configuration config = new Configuration();
        Context context = new Context(ModelType.CONDITIONAL);
        config.addContext(context);
    }

    /**
     * @Description: []
     * @Title: generate
     * @Author: Lance Ting
     * @Date: 2020-07-14
     * @Param:
     * @Return: void
     * @Throws
     */
    public void generate() throws Exception {
        Configuration config = new Configuration();
        String connectorLibPath = ConfigHelper.findConnectorLibPath(selectedDatabaseAttribute.getDbType());
        logger.info("connectorLibPath: {}", connectorLibPath);
        config.addClasspathEntry(connectorLibPath);
        Context context = new Context(ModelType.CONDITIONAL);
        config.addContext(context);

        // Table config
        TableConfiguration tableConfig = new TableConfiguration(context);
        tableConfig.setTableName(DBGenerator.getTableName());
        tableConfig.setDomainObjectName(DBGenerator.getDomainObjectName());
        //添加GeneratedKey主键生成
        if (TextUtil.isNoneEmpty(DBGenerator.getGenerateKeys())) {
            tableConfig.setGeneratedKey(new GeneratedKey(DBGenerator.getGenerateKeys(), selectedDatabaseAttribute.getDbType(), true, null));
        }

        if (DBGenerator.getMapperName() != null) {
            tableConfig.setMapperName(DBGenerator.getMapperName());
        }
        // add ignore columns
        if (ignoredColumns != null) {
            ignoredColumns.stream().forEach(ignoredColumn -> {
                tableConfig.addIgnoredColumn(ignoredColumn);
            });
        }
        if (columnOverrides != null) {
            columnOverrides.stream().forEach(columnOverride -> {
                tableConfig.addColumnOverride(columnOverride);
            });
        }
        if(!DBGenerator.isExample()){
            tableConfig.setCountByExampleStatementEnabled(false);
            tableConfig.setDeleteByExampleStatementEnabled(false);
            tableConfig.setSelectByExampleStatementEnabled(false);
            tableConfig.setUpdateByExampleStatementEnabled(false);
        }

        JDBCConnectionConfiguration jdbcConfig = new JDBCConnectionConfiguration();
        jdbcConfig.setDriverClass(DBType.valueOf(selectedDatabaseAttribute.getDbType()).getDriverClass());
        jdbcConfig.setConnectionURL(DbUtil.getConnectionUrlWithSchema(selectedDatabaseAttribute));
        jdbcConfig.setUserId(selectedDatabaseAttribute.getUsername());
        jdbcConfig.setPassword(selectedDatabaseAttribute.getPassword());
        // java model
        JavaModelGeneratorConfiguration modelConfig = new JavaModelGeneratorConfiguration();
        modelConfig.setTargetPackage(DBGenerator.getModelPackage());
        modelConfig.setTargetProject(DBGenerator.getProjectFolder() + "/" + DBGenerator.getModelPackageTargetFolder());
        // Mapper config
        SqlMapGeneratorConfiguration mapperConfig = new SqlMapGeneratorConfiguration();
        mapperConfig.setTargetPackage(DBGenerator.getMappingXMLPackage());
        mapperConfig.setTargetProject(DBGenerator.getProjectFolder() + "/" + DBGenerator.getMappingXMLTargetFolder());
        // DAO
        JavaClientGeneratorConfiguration daoConfig = new JavaClientGeneratorConfiguration();
        daoConfig.setConfigurationType("XMLMAPPER");
        daoConfig.setTargetPackage(DBGenerator.getDaoPackage());
        daoConfig.setTargetProject(DBGenerator.getProjectFolder() + "/" + DBGenerator.getDaoTargetFolder());

        context.setId("myid");
        context.addTableConfiguration(tableConfig);
        context.setJdbcConnectionConfiguration(jdbcConfig);
        context.setJdbcConnectionConfiguration(jdbcConfig);
        context.setJavaModelGeneratorConfiguration(modelConfig);
        context.setSqlMapGeneratorConfiguration(mapperConfig);
        context.setJavaClientGeneratorConfiguration(daoConfig);
        // Comment
        CommentGeneratorConfiguration commentConfig = new CommentGeneratorConfiguration();
        commentConfig.setConfigurationType(DBCommentGenerator.class.getName());
        if (DBGenerator.isComment()) {
            commentConfig.addProperty("columnRemarks", "true");
        }
        if (DBGenerator.isAnnotation()) {
            commentConfig.addProperty("annotations", "true");
        }
        context.setCommentGeneratorConfiguration(commentConfig);

        //实体添加序列化
        PluginConfiguration serializablePluginConfiguration = new PluginConfiguration();
        serializablePluginConfiguration.addProperty("type", "org.mybatis.generator.plugins.SerializablePlugin");
        serializablePluginConfiguration.setConfigurationType("org.mybatis.generator.plugins.SerializablePlugin");
        context.addPluginConfiguration(serializablePluginConfiguration);

        // limit/offset插件
        if (DBGenerator.isOffsetLimit()) {
            PluginConfiguration pluginConfiguration = new PluginConfiguration();
            pluginConfiguration.addProperty("type", "www.superbytecode.com.configuation.MysqlPluginAdapter");
            pluginConfiguration.setConfigurationType("www.superbytecode.com.configuation.MysqlPluginAdapter");
            context.addPluginConfiguration(pluginConfiguration);
        }
        context.setTargetRuntime("MyBatis3");

        List<String> warnings = new ArrayList<>();
        Set<String> fullyqualifiedTables = new HashSet<>();
        Set<String> contexts = new HashSet<>();
        ShellCallback shellCallback = new DefaultShellCallback(true); // override=true
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, shellCallback, warnings);
        myBatisGenerator.generate(progressCallback, contexts, fullyqualifiedTables);
    }

    public void setDBGenerator(www.superbytecode.com.model.DBGenerator DBGenerator) {
        this.DBGenerator = DBGenerator;
    }

    public void setDatabaseConfig(DatabaseAttribute databaseAttribute) {
        this.selectedDatabaseAttribute = databaseAttribute;
    }

    public void setProgressCallback(ProgressCallback progressCallback) {
        this.progressCallback = progressCallback;
    }

    public void setIgnoredColumns(List<IgnoredColumn> ignoredColumns) {
        this.ignoredColumns = ignoredColumns;
    }

    public void setColumnOverrides(List<ColumnOverride> columnOverrides) {
        this.columnOverrides = columnOverrides;
    }
}